package com.jxin.mall.member.service;

import cn.hutool.core.util.RandomUtil;
import com.jxin.mall.config.parent.BaseService;
import com.jxin.mall.entity.consts.HttpRspStatusEnum;
import com.jxin.mall.entity.entity.GlobalRsp;
import com.jxin.mall.member.consts.RedisKeyConsts;
import com.jxin.mall.member.consts.ServiceLogMsgConsts;
import com.jxin.mall.member.consts.LoginTypeEnum;
import com.jxin.mall.member.domain.consts.AllianceTypeEnum;
import com.jxin.mall.member.domain.service.LoginHistoryService;
import com.jxin.mall.member.domain.service.MemberUserService;
import com.jxin.mall.member.domain.service.ValidateCodeImageService;
import com.jxin.mall.member.domain.entity.LoginHistory;
import com.jxin.mall.member.domain.entity.MemberUser;
import com.jxin.mall.member.manager.LoginRegisterManager;
import com.jxin.mall.member.service.api.LoginRegisterService;
import com.jxin.mall.member.service.entity.dto.req.UserLoginReqDTO;
import com.jxin.mall.member.service.entity.dto.req.UserRegisterReqDTO;
import com.jxin.mall.member.service.entity.dto.rsp.UserLoginRspDTO;
import com.jxin.mall.middle.util.redis.RedisUtil;
import com.jxin.mall.weixin.service.entity.dto.rsp.WxUserRspDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

/**
 * 会员登入注册实现类
 * @author  蔡佳新
 * @version 1.0
 * @since   jdk 1.8
 */
@RestController
@Slf4j
public class LoginRegisterServiceImpl extends BaseService implements LoginRegisterService {
    /**登录验证码的数字个数*/
    private static final int VC_LENGTH = 5;
    /**登入验证码cookie名*/
    private static final String LOGIN_VC_IMAGE_COOKIE_NAME = "login_vc_image";
    /**cookie年龄*/
    private static final int COOKIE_AGE = 60;
    /**PC端微信回调地址*/
    private static final String PC_WX_BACK_URL = "http://jxin.natapp1.cc/member/wxAllianceLoginInPC";
    @Resource
    private MemberUserService memberUserService;
    @Resource
    private LoginRegisterManager loginRegisterManager;
    @Resource
    private LoginHistoryService loginHistoryService;
    @Resource
    private ValidateCodeImageService validateCodeImageService;
    @Resource(name = "strProtoRedisUtil")
    private RedisUtil strProtoRedisUtil;
    /**
     * 会员注册
     * @param userRegisterReqDTO 注册参数
     * @return 全局响应参数
     * @author 蔡佳新
     */
    @Override
    public GlobalRsp register(@Valid UserRegisterReqDTO userRegisterReqDTO) {
        if(StringUtils.isNotBlank(userRegisterReqDTO.getTel())){
            return loginRegisterManager.registerByPhone(userRegisterReqDTO);
        }
        if(StringUtils.isNotBlank(userRegisterReqDTO.getUsername())) {
            return loginRegisterManager.registerByUsername(userRegisterReqDTO);
        }
        return createReqParamErr();
    }

    /**
     * 会员登入
     * @param userLoginReqDTO 登入参数
     * @return 全局响应参数
     * @author 蔡佳新
     */
    @Override
    public GlobalRsp login(@Valid UserLoginReqDTO userLoginReqDTO) {
        /*
         * 校验注册码,不通过不允许登入
         */
        if(StringUtils.isNotBlank(userLoginReqDTO.getAuthCode())){
            final GlobalRsp verifyCodeRsp = loginRegisterManager.registerCodeVerify(userLoginReqDTO.getTel(), userLoginReqDTO.getAuthCode());
            if (verifyCodeRsp != null) {
                return verifyCodeRsp;
            }
        }

        final MemberUser memberUser = memberUserService.getMemberUserWhenLogin(userLoginReqDTO);
        if (memberUser == null){
            return createCustom(HttpRspStatusEnum.HTTP_RES_CODE_203.getCode(),
                                HttpRspStatusEnum.HTTP_RES_CODE_203.getName());
        }
        // QQ联合登入
        if(StringUtils.isNotBlank(userLoginReqDTO.getQqToken())){
            log.info("QQ的开发账号搞不到");
            /*do some*/
        }
        // WX联合登入
        if(StringUtils.isNotBlank(userLoginReqDTO.getWxToken())){
            final String wxCode = strProtoRedisUtil.getTokenValue(RedisKeyConsts.LOGIN_WX_USER_TOKEN,
                                                                  userLoginReqDTO.getWxToken(),
                                                                  String.class);
            if(StringUtils.isBlank(wxCode)){
                return createCustom(HttpRspStatusEnum.HTTP_RES_CODE_206.getCode(),
                                    HttpRspStatusEnum.HTTP_RES_CODE_206.getName());
            }
            final GlobalRsp relevancyGlobalRsp = loginRegisterManager
                    .userRelevancyCode(wxCode, memberUser.getUserId(), AllianceTypeEnum.WX);
           if(relevancyGlobalRsp != null){
               return relevancyGlobalRsp;
           }
        }
        /*
         * 唯一登录
         * 1.插入新的登入历史记录
         * 2.失效当前启用的登入历史记录
         * 3.删除当前启用的登入历史记录的redis的token
         */
        final String token = loginRegisterManager.onlyOneLogin(memberUser, userLoginReqDTO);
        return createSuccessWithData(UserLoginRspDTO.builder()
                                                    .nickname(memberUser.getNickname())
                                                    .gender(memberUser.getSex())
                                                    .token(token)
                                                    .build());
    }

    /**
     * 会员退出
     * @param  token 令牌
     * @return 全局响应参数
     * @author 蔡佳新
     */
    @Override
    public GlobalRsp logout(String token) {
        final LoginHistory loginHistory = loginHistoryService.getEnableLoginHistoryByToken(token);
        if(loginHistory == null){
            return createFaild();
        }
        loginRegisterManager.disableTokenAndHistory(loginHistory);
        return createSuccess();
    }

    /**
     * 获取登入验证码图片
     * @param  request  http请求
     * @param  response http响应
     * @author 蔡佳新
     */
    @Override
    public void getLoginVCImage(HttpServletRequest request, HttpServletResponse response) {
        // 删除旧的验证码图片令牌
        final Boolean removeSuccess = removeOldImageToken(request.getCookies());
        if(!removeSuccess){
            log.error(LoginRegisterServiceMsg.REMOVE_OLD_TOKEN_ERR);
        }
        final String randomCode = RandomUtil.randomNumbers(VC_LENGTH);
        final String token = strProtoRedisUtil.createToken(RedisKeyConsts.LOGIN_IMAGE_TOKEN, randomCode);
        final Cookie cookie = new Cookie(LOGIN_VC_IMAGE_COOKIE_NAME, token);
        cookie.setMaxAge(COOKIE_AGE);
        response.addCookie(cookie);
        response.setHeader(LOGIN_VC_IMAGE_COOKIE_NAME, token);
        validateCodeImageService.buildDefLineCaptchaImg(randomCode, response);
    }

    /**
     * 验证登入图形验证码
     * @param  request   http请求
     * @param  imageCode 验证码code
     * @return 全局响应对象
     * @author 蔡佳新
     */
    @Override
    public GlobalRsp validateLoginCode(HttpServletRequest request, String imageCode) {
        final String token = getTokenByCookies(request.getCookies());
        if(token == null){
            return createCustom(HttpRspStatusEnum.HTTP_RES_CODE_201.getCode(),
                                HttpRspStatusEnum.HTTP_RES_CODE_201.getName());
        }
        final Boolean hasToken = strProtoRedisUtil.hasToken(RedisKeyConsts.LOGIN_IMAGE_TOKEN, token);
        if(!hasToken){
            return createCustom(HttpRspStatusEnum.HTTP_RES_CODE_202.getCode(),
                                HttpRspStatusEnum.HTTP_RES_CODE_202.getName());
        }
        return createSuccess();
    }

    @Override
    public GlobalRsp wxAllianceLoginInPC() {
        return loginRegisterManager.wxAllianceLogin("", LoginTypeEnum.PC.getName());
    }

    @Override
    public GlobalRsp getWxAccessUrlInPC() {
        return loginRegisterManager.getWxAccessUrl(PC_WX_BACK_URL);
    }

    //****************************************private**getLoginVCImage**************************************************
    /**
     * 删除旧的验证码图片令牌
     * @param  cookieArr cookie数组
     * @return 删除老token或者没有老token 返回 <code>true</code>
     * @author 蔡佳新
     */
    private Boolean removeOldImageToken(Cookie[] cookieArr) {
        final String tokenByCookies = getTokenByCookies(cookieArr);
        if(StringUtils.isBlank(tokenByCookies)){
            return true;
        }
        return strProtoRedisUtil.removeToken(RedisKeyConsts.LOGIN_IMAGE_TOKEN, tokenByCookies);
    }
    /**
     * 根据cookie数组获取验证码token
     * @param  cookieArr cookie数组
     * @return 如果存在cookie则返回token,否则返回null
     * @author 蔡佳新
     */
    private String getTokenByCookies(Cookie[] cookieArr) {
        if(ArrayUtils.isEmpty(cookieArr)){
            return null;
        }
        String token = null;
        for (Cookie cookie : cookieArr) {
            if(LOGIN_VC_IMAGE_COOKIE_NAME.equals(cookie.getName())){
                token = cookie.getValue();
                break;
            }
        }
        return token;
    }
    //**************************************************logMsg**********************************************************
    /**
     * 日志信息常量的内部类
     * @author  蔡佳新
     * @version 1.0
     */
    private interface LoginRegisterServiceMsg{
        String REMOVE_OLD_TOKEN_ERR = ServiceLogMsgConsts.LOGIN_REGISTER_SERVICE + "老token删除失败,请检查程序是否异常";
    }
}
